<?php

// Namespace

namespace Loop;


/**
 * CApiManager is a class that handles management of APIs informations
 */

class CApiManager
{

	/**
	 * Get the apis and their description and arguments
	 *
	 * @param 	string 	$extensionId 	The extension id
	 * @param 	string 	$className 		The className
	 * @param 	string 	$directory 		The directory
	 *
	 * @return 	array 	The associative array which contains the apis description and arguments
	 */

	public function getApis($extensionId, $className = null, $directory = null)
	{
		// Check variables

		if
		(
			is_null($className) === false &&
			is_null($directory) === null
		)
		{
			e(EXCEPTION_VARIABLE_NOT_FOUND);
		}


		// There is no className and directory

		if (is_null($directory) === true)
		{
			// The array to store the files

			$files  = array();
			

			// Get the files of the extension

			$this->getFiles($extensionId, $files);
			$extensionFiles = $files[$extensionId];


			// For each file found

			foreach ($extensionFiles as $directory => $classNames) 
			{
				// For each class found

				foreach ($classNames as $className)
				{
					// Get the apis and their description

					$this->getApisInFile($extensionId, $directory, $className, $result);
					$result = $result[$extensionId];


					// For each api

					foreach ($result[$directory][$className] as $apiName => $apiDetails)
					{
						// Get the arguments

						$result[$directory][$className][$apiName] = $this->getApiArguments($apiName, $directory, $extensionId, $className);
					}
				}
			}
		}
		else
		{
			// Get the apis and their description

			$this->getApisInFile($extensionId, $directory, $className, $result);
			$result = $result[$extensionId];


			// For each api

			foreach ($result[$directory][$className] as $apiName => $apiDetails)
			{
				// Get the arguments

				$result[$directory][$className][$apiName]= $this->getApiArguments($apiName, $directory, $extensionId, $className);
			}
		}


		return $result;
	}


	/**
	 * Get the APIs from a given reflection object
	 *
	 * @param 	int 	$type 				The type of reflection method (public, private ...)
	 * @param 	object 	$objectReflection 	The reflection object, passed by reference
	 *
	 * @return 	array 	The associative array which contains the APIs informations
	 */

	private function getApiDescriptionFromReflection($type, &$objectReflection)
	{
		// Dependencies
		
		require_once(PATH_LOOP . 'Class/CDocumentation.php');
		
		
		// The array to store the APIs informations

		$result = array();


		// Get the methods

		$functions = $objectReflection->getMethods($type);


		// For each static function found

		foreach ($functions as $function) 
		{

			// Is it an api ?

			preg_match_all('/^api_.*/', $function->name, $matchesApi);

			if (count($matchesApi) == 1)
			{
				if (count($matchesApi[0]) > 0)
				{
					// Store api 

					$result[$function->name] = array();


					// Create function reflection

					$functionReflection = new \ReflectionMethod($objectReflection->name, $function->name);


					// Get the description of the function

					$docComment = $functionReflection->getDocComment();

					
					// Create object documentation 

					$documentation = new CDocumentation();
		
					
					// Does the method referer to another ?
		
					$documentation->getMethodReference($docComment);		
			

					// Analyze the description

					preg_match_all('/\s\*\s([^@]+)/', $docComment, $matchesDescription);

					if (count($matchesDescription) == 2)
					{		
						// Value of the description mask 1, index 0

						if (isset($matchesDescription[1][0]) === true)
						{
							// Remove * and multiline and useless space

							$result[$function->name]['description'] = preg_replace('/(\*\/)|\s\*|\n|(\s\s)+|(\*)+/', '', $matchesDescription[1][0]);
						}
					}	
				}
			}
		}	


		return $result;	
	}


	/**
	 * Get the list of files which contains APIs, sorted by extension
	 *
	 * @return 	array 	The list of files which contains APIs, sorted by directory and extension
	 */

	public function getApisByExtensions()
	{
		// Initializa variables

		$result = array();
		$files  = array();


		// Get ids of extensions
				
		$extensionsIds = app()->getExtensionManager()->getExtensionsIds();	


		// For each extension, get the files

		foreach ($extensionsIds as $extensionId)
		{
			// Get all the files

			$this->getFiles($extensionId, $files);
		}


		// For each file found, get the apis

		foreach ($files as $extensionId => $directories)
		{
			foreach ($directories as $directory => $filesList)
			{
				foreach ($filesList as $file)
				{
					$this->getApisInFile($extensionId, $directory, $file, $result);

				}
			}
		}


		return $result;
	}
	

	/**
	 * Try to find APIs in the given file
	 *
	 * @param 	string 	$extension 	The extension id
	 * @param 	string 	$directory 	The directory
	 * @param 	string 	$file 		The name of the file
	 * @param 	array 	The result, passed by reference
	 */

	public function getApisInFile($extensionId, $directory, $file, &$result)
	{
		
		$parentClassName = null;


		// Get the path to extension

		$pathToExtension = app()->getPathHelper()->convertExtensionIdToPath($extensionId);


		// Construct the name of the file to translate

		$fileName = $file . '.php';						


		// Define the path to the file to translate

		$pathToFile = $pathToExtension . $directory . '/' . $fileName;


		// Execute the file

		require_once($pathToFile);		


		// Construct the object

		$objectName = $file;


		// Is the class existinf?

		if (class_exists($objectName) === false)
		{
			// No, add namespace

			$namespace = str_replace('-', '\\', $extensionId);

			$objectName = $namespace . '\\' . $file;
		}


		// Instanciate the object

		$objectReflection = new \ReflectionClass($objectName);


		// Get methods public

		$result[$extensionId][$directory][$file] = $this->getApiDescriptionFromReflection(\ReflectionMethod::IS_PUBLIC, $objectReflection);
	}


	/**
	 * Get the arguments and comments of a given API
	 *
	 * @param 	string 	$apiName 		The name of the api
	 * @param 	string 	$directory 		The directory
	 * @param 	string 	$extensionId 	The extention id
	 * @param 	string 	$className 		The class name
	 *
	 * @return 	array 	An associative array which contains the APIs informations 
	 */

	public function getApiArguments($apiName, $directory, $extensionId, $className)
	{
		// Dependencies

		require_once(PATH_LOOP . 'Class/CDocumentation.php');


		// Get the object reflection

		app()->getObjectFactory()->getObjectReflection($extensionId, $className, $directory, $objectReflection, $pathToFile);


		// Instanciate the objects

		$functionReflection = new \ReflectionMethod($objectReflection->name, $apiName);


		// Create a documentation factory object

		$documentation = new CDocumentation();


		// Get function description

		$docComment = $functionReflection->getDocComment();
		
		
		// Does the method referer to another ?
		
		$documentation->getMethodReference($docComment);		


		// Get the params

		$params['comment'] = $docComment;


		// Get the description

		$params['infos'] = $documentation->getMethodDescription($docComment);


		// Get the params

		$params['arguments'] = $documentation->getMethodArguments($docComment);


		// Get the param return 

		$params['return'] = $documentation->getMethodReturn($docComment);	
		
		
		// Get the params

		$params['call'] = $documentation->getMethodCall($docComment);		


		return $params;
	}


	/**
	 * Get the list of files (sorted by directory) of the given extension
	 *
	 * @param 	string 	$extensionId 	The extension id
	 * @param 	array 	$files 			The list of files, passed by reference
	 */

	public function getFiles($extensionId, &$files)
	{
		// Directories

		$directories = pref('[Loop]/APIs/directories');		


		// Get the allowed extensions

		$allowedExtensions =  pref('[Loop]/APIs/allowedExtensions');


		// Get the path to extension

		$pathToExtension = app()->getPathHelper()->convertExtensionIdToPath($extensionId);


		// For each directory

		foreach ($directories as $directory)
		{
			// Open the directory

			$trunkDirectory = opendir($pathToExtension . $directory);


			// Get the directory's files

			$filesInDirectory= scandir($pathToExtension . $directory);


			// For each file found

			foreach ($filesInDirectory as $fileInDirectory)
			{
				// Is it a directory ?

				if (is_dir($fileInDirectory))
				{
					continue;
				}


				// Get the extension

				$extension = '.' . pathinfo($pathToExtension . $directory . $fileInDirectory , PATHINFO_EXTENSION);


				// Is the extention allowed ?

				if (array_search($extension, $allowedExtensions) === false)
				{
					// The extension is not allowed

					continue;
				}			


				// Calcul the length of the extension

				$length = strlen($extension);


				// Get the name of the file without extension

				$fileName = substr($fileInDirectory, 0, -$length);
				

				// Does the filename already exist in the array ?

				if (array_search($fileName, $files) !== false)
				{
					// The directory is excluded

					continue;
				}
				

				// Special case Loop/Proxy.php

				if
				(
					$fileName == 'Proxy' &&
					$extensionId == 'Loop' &&
					$directory == 'Class'
				)
				{
					continue;
				}	


				// Store the file name

				$files[$extensionId][$directory][] = $fileName;
			}
		}

		// Sort the files

		ksort($files);


		return $files;
	}		
}

?>